<template>
  <div class="slider" ref="slider">
    <div class="slider-group" ref="sliderGroup">
      <slot>
      </slot>
    </div>
    <div class="dots">
      <span class="dot" v-for="(item,index) in dots" :key="index" :class="{'active':currentPageIndex===index}"></span>
    </div>
  </div>
</template>

<script>
  import BScroll from 'better-scroll'
  import {addClass} from 'common/js/dom'                  // 会有很多地方应用到改dom方法，于是根据模块化开发思想，抽象出来编写在dom.js文件中

  export default {
    data () {
      return {
        dots: [],
        currentPageIndex: 0
      }
    },
    props: {
      loop: {                 // 自动轮播
        type: Boolean,
        default: true
      },
      autoPlay: {             // 循环轮播
        type: Boolean,
        default: true
      },
      interval: {             // 轮播间隔
        type: Number,
        default: 4000
      }
    },
    mounted () {
      setTimeout(() => {       // 浏览器刷新时间一般是17毫秒
        this._setSliderWidth()     // 方法写在methods里面，容易维护 。。。 一开始不传参数等于传undefined
        this._initDots()        // _initDocs必须在_initSlider之前。因为为了做到无缝轮播效果，BScroll初始化的时候给img多复制了一前一后两个。这个时候dom是有7个img元素的。实际上有两个重复的。所以在初始化BScroll之前先初始化img数量
        this._initSlider()
        if (this.autoPlay) {
          this._play()            // 自动播放
        }
      }, 20)

      window.addEventListener('resize', () => {       // 监听视口变化事件
        if (!scroll) {                                // 如果scroll没绑定好，那么什么都不做
          return
        }
        this._setSliderWidth(true)                        // 重新计算宽度
        this.scroll.refresh()
      })
    },
    methods: {
      _setSliderWidth (isResize) {
        this.children = this.$refs.sliderGroup.children          // this.$refs.sliderGroup 是 DOM 对象 .children获取子元素  。。。 此处给vue加了一个属性children。this.children.length = 5
        let width = 0
        let sliderWidth = this.$refs.slider.clientWidth          // clientWidth网页可见区域宽
        for (let i = 0; i < this.children.length; i++) {
          let child = this.children[i]
          addClass(child, 'slider-item')                         // 循环遍历dom，并给每一个li添加class,暂时没有实现，页面dom元素上没有添加该class。因为slot里面的内容加载的更晚。promise异步加载的可能会有几百毫秒延时
          child.style.width = sliderWidth + 'px'    // 给原生js设置宽度要加上单位
          width += sliderWidth
        }
        if (this.loop && !isResize) {                                 // 如果是循环滚动的话，会一前一后添加两个dom元素 。。。 加了一个判断。如果是初次计算宽度需要加上2个img宽度，如果是重计算那么久没必要再加这个宽度了
          width += 2 * sliderWidth                       // 宽度也要增加两个li的宽度
        }
        this.$refs.sliderGroup.style.width = width + 'px'  // 给原生js设置宽度要加上单位
      },
      _initSlider () {
        this.scroll = new BScroll(this.$refs.slider, {
          scrollX: true,
          scrollY: false,
          momentum: false,               // 惯性，设置为否。去掉弹性跳的
          snap: true,                    // 该属性是给 slider 组件使用的，普通的列表滚动不需要配置
          snapLoop: this.loop,
          snapThreshold: 0.3,            // 用手指滑动时页面可切换的阈值，大于这个阈值可以滑动的下一页
          snapSpeed: 400                 // 轮播图切换的动画时间
          // click: true                    // 移动端有的地方BScroll点击事件会和a标签等默认跳转事件有冲突。要注意
        })

        this.scroll.on('scrollEnd', () => {  // scroll滚动结束会触发一个事件。scrollEnd
          let pageIndex = this.scroll.getCurrentPage().pageX       // this.scroll.getCurrentPage()返回的对象里面pageX属性值是某元素集合的length
          if (this.loop) {         // 如果是循环的。那么就是一前一后加了2个元素所以最终下标
            pageIndex -= 1
          }
          this.currentPageIndex = pageIndex

          if (this.autoPlay) {              // 在每次切换img结束
            clearTimeout(this.timer)        // 清除之前的clearTimeout
            this._play()                    // 再次运行
          }
        })
      },
      _initDots () {
        this.dots = new Array(this.children.length)                   // dots初始化为一个长度为5的空数组
      },
      _play () {
        let pageIndex = this.currentPageIndex + 1                    // 一般情况 this.currentPageIndex++
        if (this.loop) {                                             // 循环的话 this.currentPageIndex还要再加一次
          pageIndex += 1
        }
        this.timer = setTimeout(() => {                             // 设置定时器
          this.scroll.goToPage(pageIndex, 0, 400)                           // 调用BScroll的方法goToPage(index) -> 跳转到对应下标位置 。。。0->代表Y轴方向的 。。。 400毫秒跟之前设置的BScroll->options->snapSpeed 的值保持一致
        }, this.interval)                                           // 时间间隔是props设置的时间
      }
    },
    beforeDestroyed () {                              // 在销毁的时候。   切换组件
      clearTimeout(this.timer)                        // 停止定时器。做了一个优化。
    },                                                 // 加入组件里面设计到计时器，那么在销毁的时候也要关闭它，有助于释放内存
    activated () {                              // ****生命周期，keep-alive激活的时候调用
      if (this.autoPlay) {              // 在每次切换img结束
        clearTimeout(this.timer)        // 清除之前的clearTimeout
        this._play()                    // 再次运行
      }
    },
    deactivated () {                            // ****生命周期，keep-alive激活的时候调用
      clearTimeout(this.timer)
    }
  }
</script>

<style scoped lang="stylus" rel="stylesheet/stylus">
  @import "~common/stylus/variable"

  .slider
    min-height: 1px
    .slider-group
      position: relative
      overflow: hidden
      white-space: nowrap                      // 强制在一行排列，不让换行
      .slider-item
        float: left
        box-sizing: border-box
        overflow: hidden
        text-align: center
        a
          display: block
          width: 100%
          overflow: hidden
          text-decoration: none
        img
          display: block
          width: 100%
    .dots
      position: absolute
      right: 0
      left: 0
      bottom: 12px
      text-align: center
      font-size: 0
      .dot
        display: inline-block
        margin: 0 4px
        width: 8px
        height: 8px
        border-radius: 50%
        background: $color-text-l
        &.active
          width: 20px
          border-radius: 5px
          background: $color-text-ll
</style>